#include "glare.core.RenderWindow.h"
#include "glare.core.Driver.h"
#include "glare.core.StringConverter.h"
#include "glare.core.PlatformWindow.h"

namespace Glare {

	RenderWindow::RenderWindow(PlatformWindow* platform_window) 
		: _is_initialized(false)
		, _is_fullscreen(false)
		, _present_sync_interval(0)
		, _platform_window(platform_window)
	{
	}

	RenderWindow::~RenderWindow()
	{

	}

	void RenderWindow::Initialize()
	{
		if (_is_initialized)
			return;

		InitializeImpl();
		_is_initialized = true;
	}

	const uint RenderWindow::GetCanvasWidth() const
	{
		if (_platform_window)
			return _platform_window->GetCanvasWidth(this);

		GetDriver()->WriteLog("RenderWindow::GetCanvasWidth: unable to determine canvas width, returning 0 as default", LMT_Error);
		return 0;
	}

	const uint RenderWindow::GetCanvasHeight() const
	{
		if (_platform_window)
			return _platform_window->GetCanvasHeight(this);

		GetDriver()->WriteLog("RenderWindow::GetCanvasWidth: unable to determine canvas width, returning 0 as default", LMT_Error);
		return 0;
	}

	PlatformWindow* RenderWindow::GetPlatformWindow() const
	{
		return _platform_window;
	}

	const bool& RenderWindow::IsInitialized() const
	{
		return _is_initialized;
	}

	const bool& RenderWindow::IsFullscreen() const
	{
		return _is_fullscreen;
	}

	void RenderWindow::SetFullscreen(const bool& fullscreen)
	{
		if (fullscreen == _is_fullscreen)
			return;

		SetFullscreenImpl(fullscreen);
		_is_fullscreen = fullscreen;
	}

	const uint& RenderWindow::GetPresentSyncInterval() const
	{
		return _present_sync_interval;
	}

	void RenderWindow::SetPresentSyncInterval(const uint& interval)
	{
		_present_sync_interval = interval;
	}

	bool RenderWindow::SetOption(const string& name, const string& value)
	{
		ConfigOptionMap::iterator it = _config_options.find(name);

		if (it == _config_options.end())
			return false;

#ifdef _DEBUG
		// TODO: check if value is a possible value
#endif

		// this RenderWindow is already initialized, can't change this option anymore
		if (_is_initialized && it->second.Immutable)
			return false;

		SetOptionImpl(name, value);
		it->second.CurrentValue = value;
		return true;
	}

	bool RenderWindow::SetOption(const string& name, const int& value)
	{
		string string_value = StringConverter::ToString(value);
		return SetOption(name, string_value);
	}

	bool RenderWindow::AddConfigOption(const ConfigOption& option)
	{
		ConfigOptionMap::iterator it = _config_options.find(option.Name);

		if (it != _config_options.end())
			return false;

		_config_options.insert(ConfigOptionMap::value_type(option.Name, option));
		return true;
	}

	bool RenderWindow::AddConfigOption(const string& name, const string& initial_value, const bool& immutable, const string possible_values[], int num_values, const string& info_url)
	{
		// perform an early abort if the option already exists
		ConfigOptionMap::iterator it = _config_options.find(name);

		if (it != _config_options.end())
			return false;

		ConfigOption option;

		option.Name = name;
		option.CurrentValue = initial_value;
		option.Immutable = immutable;
		option.InfoUrl = info_url;

		for (int i = 0; i < num_values; ++i)
			option.PossibleValues.push_back(possible_values[i]);

		return AddConfigOption(option);
	}

#if GLARE_CXX_11_FEATURES_ENABLED
	bool RenderWindow::AddConfigOption(const string& name, const string& initial_value, const bool& immutable, std::initializer_list<string> possible_values, const string& info_url)
	{
		// perform an early abort if the option already exists
		ConfigOptionMap::iterator it = _config_options.find(name);

		if (it != _config_options.end())
			return false;

		ConfigOption option;

		option.Name = name;
		option.CurrentValue = initial_value;
		option.Immutable = immutable;
		option.PossibleValues.insert(option.PossibleValues.begin(), possible_values.begin(), possible_values.end());
		option.InfoUrl = info_url;

		return AddConfigOption(option);
	}
#endif

	const ConfigOptionMap& RenderWindow::GetOptions() const
	{
		return _config_options;
	}
}
